package com.itheima.service.Impl;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.converters.longconverter.LongStringConverter;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.common.ApplicationContext;
import com.itheima.dto.OrdersDto;
import com.itheima.mapper.*;
import com.itheima.pojo.*;
import com.itheima.result.R;
import com.itheima.service.OrdersDtoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: 斌
 * @DateTime: 2023年02月12日  21:06:58
 * @Description: com.itheima.service.Impl
 * @Version: 1.0
 */
@Slf4j
@Service
public class OrdersDtoServiceImpl implements OrdersDtoService {
    @Autowired
    private OrdersDao ordersDao;
    @Autowired
    private OrderDetailDao orderDetailDao;
    @Autowired
    private ShoppingCartDao shoppingCartDao;
    @Autowired
    private AddressBookDao addressBookDao;
    @Autowired
    private UserDao userDao;

    @Override
    public R submitOrder(Orders orders) {
        // 总思路，根据user_Id和addressBook_Id去数据库查询有关数据，并封装到orders和orderDetail中，shoppingCart
        //获取用户id
        Long userId = (Long) ApplicationContext.getData();
        //根据用户id获取所属购物车数据
        LambdaQueryWrapper<ShoppingCart> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(userId != null, ShoppingCart::getUserId, userId);
        List<ShoppingCart> shoppingCarts = shoppingCartDao.selectList(wrapper);

        //用IdWorker生成订单id，不然你无法获取订单订单id，订单明细表中需要订单id
        long orderId = IdWorker.getId();
        // 总价，进行每个菜品数量*单价 进行累加而得
        BigDecimal amount = new BigDecimal(0);
        //遍历购物车数据，并进行计算，然后封装到订单明细表
        for (ShoppingCart shoppingCart : shoppingCarts) {
            //封装一条插一条
            OrderDetail orderDetail = new OrderDetail();
            //    获得每样菜品下单的数量
            BigDecimal number = new BigDecimal(shoppingCart.getNumber());
            //   设置每个订单明细表的订单id
            orderDetail.setOrderId(orderId);
            //   计算
            //    从购物车中获取价格
            BigDecimal price = new BigDecimal(String.valueOf(shoppingCart.getAmount()));
            //    相乘得出订单明细表的该条订单的总金额
            //    set到orderDetail中
            orderDetail.setAmount(price.multiply(number));
            //    累加，封装总金额，这里的add只是进行了“加”操作，累加需要个变量来接
            amount = amount.add(orderDetail.getAmount());
            //    插入
            BeanUtils.copyProperties(shoppingCart, orderDetail);
            orderDetailDao.insert(orderDetail);
        }
        //根据前台传来的地址Id获取地址数据.eq(orders.getAddressBookId() != null,AddressBook::getId,orders.getAddressBookId())
        // 3、根据地址id查询地址数据 select * from address_book where id = ?
        AddressBook one = addressBookDao.selectById(orders.getAddressBookId());

        //需要从user表获取当前用户信息，谁下的单
        User user = userDao.selectById(userId);

        //对订单表进行数据封装
        if (one != null) {
            orders.setId(orderId);
            orders.setNumber(String.valueOf(orderId));
            orders.setStatus(2);
            orders.setUserId(userId);
            orders.setAddressBookId(orders.getAddressBookId());
            orders.setOrderTime(LocalDateTime.now());
            orders.setCheckoutTime(LocalDateTime.now());
            orders.setAmount(amount);
            orders.setUserName(user.getName());
            //收货人的电话，用户的电话不一定和收货人电话一样
            orders.setPhone(one.getPhone());
            orders.setConsignee(one.getConsignee());
            //封装地址时，要从省--市--区--详细地址，要进行非空判断，xxx==null ？"":具体名称
            orders.setAddress((one.getProvinceName() == null ? "" : one.getProvinceName())
                    + (one.getCityName() == null ? "" : one.getCityName())
                    + (one.getDistrictName() == null ? "" : one.getDistrictName())
                    + (one.getDetail() == null ? "" : one.getDetail()));
            ordersDao.insert(orders);
            //封装完成后，清空购物车数据
            //    delete from shoppingCart where userId = ?
            LambdaQueryWrapper<ShoppingCart> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(userId != null, ShoppingCart::getUserId, userId);
            shoppingCartDao.delete(lambdaQueryWrapper);
        }


        return R.success("下单成功");
    }

    @Override
    public R pageOrder(Integer page, Integer pageSize) {

        Page<OrdersDto> ordersDtoPage = new Page<>();
        Page<Orders> ordersPage = new Page<>();
        Long userId = (Long) ApplicationContext.getData();
        LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(userId != null, Orders::getUserId, userId);
        Page<Orders> selectPage = ordersDao.selectPage(ordersPage, wrapper);
        BeanUtils.copyProperties(selectPage, ordersDtoPage, "records");

        //订单详细信息
        //queryWrapper

        List<OrdersDto> ordersDtoList = selectPage.getRecords().stream().map(orders -> {
            OrdersDto ordersDto = new OrdersDto();
            LambdaQueryWrapper<OrderDetail> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(orders.getId() != null, OrderDetail::getOrderId, orders.getId());
            List<OrderDetail> orderDetails = orderDetailDao.selectList(queryWrapper);
            ordersDto.setOrderDetails(orderDetails);
            BeanUtils.copyProperties(orders, ordersDto);

            return ordersDto;
        }).collect(Collectors.toList());
        ordersDtoPage.setRecords(ordersDtoList);

        return R.success(ordersDtoPage);
    }

    @Override
    public R ordersPage(Integer page, Integer pageSize, Long number, String beginTime, String endTime) {

        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date begin = null;
            if (beginTime != null) {
                begin = simpleDateFormat.parse(beginTime);
            }
            Date end = null;
            if (endTime != null) {
                end = simpleDateFormat.parse(endTime);
            }
            //SELECT * FROM orders WHERE order_time >= "2023-02-13 17:38:02"
            //AND checkout_time <= "2023-02-13 17:38:02"
            LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>();
            wrapper.like(number != null, Orders::getNumber, number)
                    .ge(beginTime != null, Orders::getOrderTime, begin)
                    .le(endTime != null, Orders::getCheckoutTime, end);

            Page<Orders> ordersPage = new Page<>();
            Page<Orders> selectPage = ordersDao.selectPage(ordersPage, wrapper);
            return R.success(selectPage);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public R updateStatus(Orders orders) {
        //前端传回的状态码，在实体类orders里了，框架会根据传回的状态，动态的修改status
        log.info("前端传回的状态码:{}", orders.getStatus());
        LambdaUpdateWrapper<Orders> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(orders.getId() != null, Orders::getId, orders.getId());
        int updateResult = ordersDao.update(orders, wrapper);
        return updateResult > 0 ? R.success("订单状态修改成功") : R.error("订单状态修改失败");
    }

    @Override
    public R againOrders(Orders orders) {
        //执行再来一单时，应先清空购物车
        Long userId = (Long) ApplicationContext.getData();
        LambdaQueryWrapper<ShoppingCart> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(userId != null, ShoppingCart::getUserId, userId);
        shoppingCartDao.delete(queryWrapper);
        //查询再来一单的订单明细表的具体数据
        LambdaQueryWrapper<OrderDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(orders.getId() != null, OrderDetail::getOrderId, orders.getId());
        List<OrderDetail> orderDetails = orderDetailDao.selectList(wrapper);
        int sum = 0;
        for (OrderDetail orderDetail : orderDetails) {
            //   根据ororderDetail里的数据对shoppingCart进行封装
            ShoppingCart shoppingCart = new ShoppingCart();
            shoppingCart.setAmount(orderDetail.getAmount());
            shoppingCart.setUserId(userId);
            shoppingCart.setNumber(orderDetail.getNumber());
            shoppingCart.setImage(orderDetail.getImage());
            shoppingCart.setDishId(orderDetail.getDishId());
            shoppingCart.setSetmealId(orderDetail.getSetmealId());
            shoppingCart.setName(orderDetail.getName());
            shoppingCart.setDishFlavor(orderDetail.getDishFlavor());
            shoppingCart.setCreateTime(LocalDateTime.now());
            int insertResult = shoppingCartDao.insert(shoppingCart);
            sum += insertResult;
        }
        return sum > 0 ? R.success("添加购物车成功") : R.error("添加购物车失败");
    }

    @Override
    public void exportOrders(HttpServletResponse response) {

        LambdaQueryWrapper<Orders> wrapper = new LambdaQueryWrapper<>();
        List<Orders> orders = ordersDao.selectList(wrapper);
        ArrayList<OrderSheet> orderSheets = new ArrayList<>();
        for (Orders order : orders) {
            OrderSheet orderSheet = new OrderSheet();
            orderSheet.setOrderTime(order.getOrderTime());
            orderSheet.setStatus(order.getStatus());
            orderSheet.setPhone(order.getPhone());
            orderSheet.setAddress(order.getAddress());
            orderSheet.setNumber(order.getNumber());
            orderSheet.setAmount(order.getAmount());
            orderSheet.setUserName(order.getUserName());
            orderSheets.add(orderSheet);
        }
        /*
         * 文件下载（失败了会返回一个有部分数据的Excel）
         * <p>
         * 1. 创建excel对应的实体对象 参照{@link DownloadData}
         * <p>
         * 2. 设置返回的 参数
         * <p>
         * 3. 直接写，这里注意，finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
         */
        // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        response.setHeader("订单明细.xlsx", "Content-Disposition");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = null;
        try {

            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置背景颜色
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            //设置头字体
            WriteFont headWriteFont = new WriteFont();
            headWriteFont.setFontHeightInPoints((short) 13);
            headWriteFont.setBold(true);
            headWriteCellStyle.setWriteFont(headWriteFont);
            //设置头居中
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

            //内容策略
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置 水平居中
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);

            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);


            fileName = URLEncoder.encode("订单数据", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            try {
                EasyExcel.write(response.getOutputStream(), OrderSheet.class)
                        .registerConverter(new LongStringConverter())
                        .registerWriteHandler(horizontalCellStyleStrategy)
                        .sheet("模板").doWrite(orderSheets);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }

    }
}
